﻿using DataMonitor_Tools.Tools;
using DataMonitor_Tools.Tools.SMTP;
using DataMonitorMysql.MappingClass;
using DataMonitorWebApi.Utility;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataMonitorWebApi.Quartz
{
    public class MyJob : IJob
    {
        private readonly ILogger<MyJob> _logger;
        private readonly IMemoryCache _memoryCache;//内存缓存
        private readonly IHubContext<SiginalrHub> _hubContext;//signalr
        public MyJob(ILogger<MyJob> logger, IMemoryCache memoryCache, IHubContext<SiginalrHub> hubContext)
        {
            _logger = logger;
            _memoryCache = memoryCache;
            _hubContext = hubContext;
        }
        public async Task Execute(IJobExecutionContext context)
        {
            var map = context.JobDetail.JobDataMap;
            string? path = map.GetString("datapath");
            //_logger.LogWarning($"开启定时监控路径：{path}");
            Console.WriteLine ($"{path} in {Thread.CurrentThread.ManagedThreadId} run at {DateTime.Now}");
            var userprop = _memoryCache.Get<dm_props_user>(path);
            var adminprop = _memoryCache.Get<dm_props_admin>("datamonitoradminpara");
            //获得当天日期文件夹路径
            string watchpath = Path.Combine(path, DateTime.Now.ToString("MM_dd"));
            //获得最新的csv文件
            var file = FileOperator.GetLatestextFiles(watchpath, "*.csv").LastOrDefault();
            //获得缓存里的文件名
            var lastfilename= _memoryCache.Get<string>(path + "filename");
            //比较最新产生的文件名是否跟缓存里的一样，一样说明没有新文件产生
            if(file!=null)
            {
                if (file.Name != lastfilename)
                {
                    if (userprop != null && adminprop != null)
                    {
                        //最新文件名存入缓存中
                        await Console.Out.WriteLineAsync($"监控到新文件{file.Name}");
                        _memoryCache.Set<string>(path + "filename", file.Name);
                        var structall = await CSVFileWatch.CSVFileWatchCSVAsyncV2(file.FullName, file.Name, adminprop.reducetimes);
                        switch (structall.status)
                        {
                            case 0:
                                var lastingtime = adminprop.points / adminprop.sample;//csv文件的持续时间
                                var spdidx = structall.headers.IndexOf("spd");
                                List<double> spd = new List<double>();
                                double spdavg = 0;//平均速度
                                double sumdistance = 0;//单个文件的里程数
                                if (spdidx != -1)
                                {
                                    spd = structall.alldatalist[structall.headers.IndexOf("spd")];
                                    spdavg = await CSVFileWatch.CalSpdAverageAsync(spd);
                                    sumdistance = Math.Round(spdavg / 3600 * lastingtime, 2);
                                }
                                var chartall = await CSVFileWatch.CSVFileWatchStructEditAsync(structall, userprop);//图表数据

                                //获得缓存里的日期，就是监控开始的日期
                                var datetime = _memoryCache.Get<DateTime>(userprop.watchpath + "datetime");
                                //获得当前日期
                                var nowtime = DateTime.Now;
                                //获得他们之间的日期差，并把这些中间的日期的缓存清除掉
                                var datespan = DateTimeOperator.GetDateStringsBetweenDates(datetime, nowtime);
                                for (int i = 0; i < datespan.Length; i++)
                                {
                                    _memoryCache.Remove(userprop.vehicle + datespan[i] + "sumdistance");
                                    _memoryCache.Remove(userprop.vehicle + datespan[i] + "filecount");
                                }

                                //获得缓存里前一次的累计里程，这里需要用到GetOrCreate，因为过了一天日期就不同了，需要重新创建累计里程缓存
                                var lastsumdis = _memoryCache.GetOrCreate<double>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance", value =>
                                {
                                    return 0;
                                });
                                //获得缓存里前一次的文件数目
                                var filecount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount", value =>
                                {
                                    return 0;
                                });
                                //设置缓存里这一次的累计里程和文件数
                                _memoryCache.Set<double>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance", lastsumdis + sumdistance);
                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount", filecount + 1);
                                var sdsent = _memoryCache.Get<double>((userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance"));
                                var countsent = _memoryCache.Get<int>((userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount"));
                                #region 开始发送数据
                                foreach (var i in SiginalrHub.user)
                                {
                                    await _hubContext.Clients.Group(i).SendAsync("csvfileinfo", chartall, structall.name, spdavg, sdsent, countsent, userprop.watchpath);
                                }
                                //创建异常邮件内容
                                var res = SMTPWarnContent.CreateWarnContent(structall, userprop.vehicle, adminprop.accerrorvalue, adminprop.diserrorvalue);
                                //先判断有没有异常，没有就不用费劲去看字典了
                                if (res != "")
                                {
                                    //先获得mailconfig缓存
                                    var mailconfig = _memoryCache.Get<SMTPConfig>(userprop.vehicle + "mailconfig");
                                    if (mailconfig != null)
                                    {
                                        //再从缓存里看有没有mailerror，如果没有说明第一次碰到error
                                        var firstmailerror = _memoryCache.Get<string>(userprop.vehicle + "mailerror");
                                        if (firstmailerror == null)
                                        {
                                            //第一次碰到错误发送邮件
                                            await SMTPMail.SendEmailAsync(mailconfig, res);
                                            //如果第一次碰到，则创建缓存并设置为第一次的错误信息
                                            var mailerror = _memoryCache.GetOrCreate<string>(userprop.vehicle + "mailerror", value =>
                                            {
                                                return res;
                                            });
                                            //再创建缓存记录第一次发送的时间
                                            var starttime = _memoryCache.GetOrCreate<DateTime>(userprop.vehicle + "sendtime", value =>
                                            {
                                                return DateTime.Now;
                                            });
                                        }
                                        //说明缓存里已经有mailerror了，不是第一次出现问题了
                                        else
                                        {
                                            //判断当前的与上一次的是否问题一致，不一致再发邮件，再覆盖记录发送时间
                                            if (res != firstmailerror)
                                            {
                                                _memoryCache.Set<string>(userprop.vehicle + "mailerror", res);
                                                await SMTPMail.SendEmailAsync(mailconfig, res);
                                                _memoryCache.Set<DateTime>(userprop.vehicle + "sendtime", DateTime.Now);
                                            }
                                            //如果一致，则判断是否经过了1小时，然后再发送邮件提醒
                                            else
                                            {
                                                //先获取上一次缓存里的发送时间
                                                var lastsendtime = _memoryCache.Get<DateTime>(userprop.vehicle + "sendtime");
                                                if (SMTPWarnContent.IsPastOneHour(lastsendtime, mailconfig.emailtimespan))
                                                {
                                                    await SMTPMail.SendEmailAsync(mailconfig, res);
                                                    _memoryCache.Set<DateTime>(userprop.vehicle + "sendtime", DateTime.Now);
                                                }
                                            }
                                        }
                                    }
                                }
                                #endregion
                                break;
                            case 1:
                                _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件有空值或nan");
                                break;
                            case 2:
                                _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件大小为0kb");
                                break;
                            case 3:
                                _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件被占用");
                                break;
                            case 9:
                                _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件读取错误，请查看错误日志");
                                break;
                        }

                    }

                }
            }
            

            
        }
    }
}
